package com.ficus.road.maintain.service;

import com.aliyun.oss.model.OSSObject;
import com.ficus.road.maintain.config.DiseaseConfig;
import com.ficus.road.maintain.config.DiseaseConfigInfo;
import com.ficus.road.maintain.core.exception.BadRequestException;
import com.ficus.road.maintain.core.model.*;
import com.ficus.road.maintain.core.model.oss.AliyunOssResult;
import com.ficus.road.maintain.dao.*;
import com.ficus.road.maintain.third.zh.roadgps.ZHRoadName;
import com.ficus.road.maintain.util.AliyunOSSUtil;
import com.ficus.road.maintain.util.BaiduMapClient;
import com.ficus.road.maintain.util.IdGeneratorUtil;
import com.ficus.road.maintain.util.ImageUtil;
import com.google.common.collect.Lists;
import ficus.car_demo.FrameMeta;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xiawen yang
 * @date 2021/10/11 上午10:34
 */
@Service
@Slf4j
public class InspectService {

    @Getter
    private Map<String, String> carCompanyMap = new HashMap<>();
    @Getter
    private Map<String, String> companyNameMap = new HashMap<>();
    @Autowired
    private InspectPictureDao inspectPictureDao;
    @Autowired
    private HitDao hitDao;
    @Autowired
    private DiseaseConfig diseaseConfig;
    @Autowired
    private GpsHistoryDao gpsHistoryDao;
    @Autowired
    private CarDao carDao;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private ZhonghaiClient zhonghaiClient;
    @Autowired
    private ZHRoadName zhRoadName;
    @Autowired
    private BaiduMapClient baiduMapClient;

    @Autowired
    private AliyunOSSUtil aliyunOSSUtil;

    @PostConstruct
    public void init() {
        List<Car> all = carDao.findAll();
        carCompanyMap = all.stream().collect(Collectors.toMap(Car::getId, Car::getHandleCompany));
        List<Company> all1 = companyDao.findAll();
        companyNameMap = all1.stream().filter(item -> ObjectUtils.isNotEmpty(item.getName())).collect(Collectors.toMap(Company::getId, Company::getName));
    }

    public List<InspectPictureVO> queryLesionInfo(Query query) {
        List<InspectPicture> inspectPictures = inspectPictureDao.findByQuery(query);
        List<InspectPictureVO> res = new ArrayList<>();
        inspectPictures.sort(Comparator.comparing(InspectPicture::getTimeStamp));
        inspectPictures.forEach(inspectPicture -> {
            InspectPictureVO inspectPictureVO = InspectPictureVO.builder()
                    .pictureId(inspectPicture.getId()).url(inspectPicture.getUrl())
                    .lesions(inspectPicture.getLesions()).build();
            res.add(inspectPictureVO);
        });
        return res;
    }

    public String updateLesionInfo(InspectPictureVO inspectPictureVO) throws IOException {
        InspectPicture fetch = inspectPictureDao.fetch(inspectPictureVO.getPictureId());
        List<String> hitIds;
        if (ObjectUtils.isEmpty(fetch)) {
            throw new BadRequestException("pictureId is illegal");
        }
        //修改前先删除hit表中的hit
        if (ObjectUtils.isNotEmpty(fetch.getLesions())) {
            hitIds = fetch.getLesions().stream().map(Lesion::getHitId).collect(Collectors.toList());
            hitIds.forEach(hitId -> {
                if (Objects.nonNull(hitId)) {
                    Hit hit = hitDao.fetch(hitId);
                    if (Objects.nonNull(hit)) {
                        hit.getAttrs().getConfirmation().setStatus(Confirmation.ConfirmationStatus.DELETE);
                        hitDao.saveOrUpdate(hit);
                    }
                }
            });
        }
        List<Lesion> lesions = inspectPictureVO.getLesions();
        if (lesions.size() == 0) {
            fetch.setLesions(null);
            fetch.setFlag(2);
        } else {
            fetch.setLesions(lesions);
            fetch.setFlag(1);
            for (int i = 0; i < lesions.size(); i++) {
                String hitId = createInspectHits(lesions.get(i), fetch, i);
                if ("-1".equals(hitId)) {
                    return "-1";
                }
                if (StringUtils.isNotEmpty(hitId)) {
                    lesions.get(i).setHitId(hitId);
                }
            }
        }
        inspectPictureDao.saveOrUpdate(fetch);
        return inspectPictureVO.getPictureId();
    }

    private String createInspectHits(Lesion lesion, InspectPicture inspectPicture, Integer idx) throws IOException {
        Integer limitHour = 0;
        DiseaseConfigInfo diseaseConfigInfo = diseaseConfig.getMap().get(lesion.getType());
        Integer loop = 1;
        String classification = "SECURITY";
        String scene = "CITY";
        if (Objects.nonNull(diseaseConfigInfo)) {
            limitHour = diseaseConfigInfo.getLimitHour();
            loop = diseaseConfigInfo.getLoop();
            classification = diseaseConfigInfo.getClassification();
            scene = diseaseConfigInfo.getScene();
        }
        long timestamp = inspectPicture.getTimeStamp() / 1000;
        Query queryGpsLocation = new Query(Criteria.where("car_id").is(inspectPicture.getCarId()).and("timestamp").gte(timestamp).and("longitude").ne(0));
        queryGpsLocation.with(new Sort(Sort.Direction.ASC, "timestamp")).skip(0).limit(1);
        GpsHistory history = gpsHistoryDao.findOne(queryGpsLocation);
        GpsLocation gpsLocation;
        if (Objects.isNull(history)) {
            //经纬度是0，不创建
            throw new RuntimeException("查询不到当前图片的gps坐标");
        }
        if (history.getLongitude().equals(0d) || history.getLatitude().equals(0d)) {
            return "-1";
        }
        gpsLocation = GpsLocation.builder().longitude(history.getLongitude()).latitude(history.getLatitude()).build();
        String companyId = carCompanyMap.get(inspectPicture.getCarId());
        String companyName = companyNameMap.get(companyId);
        long l1 = System.currentTimeMillis();
        String roadInfo = zhRoadName.getRoadName(gpsLocation);
        if (StringUtils.isBlank(roadInfo) || StringUtils.isBlank(roadInfo.split(",")[0])) {
            long l2 = System.currentTimeMillis();
            String streetName = baiduMapClient.geocoder(gpsLocation);
            log.error("获取中海道路信息异常, 接口耗时: {}s; 百度地图接口耗时: {} ms", (l2 - l1) / 1000, System.currentTimeMillis() - l2);
            roadInfo = streetName + (StringUtils.isBlank(roadInfo) ? "" : roadInfo);
        }
        Hit hit = new Hit();
        String hitId = inspectPicture.getCarId() + IdGeneratorUtil.generatorId();
        hit.setId(hitId);
        hit.setType(lesion.getType());
        hit.setHitTime(timestamp);
        hit.setFirstHitTime(timestamp);
        int width = lesion.getWidth() != null ? lesion.getWidth().intValue() : 0;
        float length = lesion.getLength() != null ? lesion.getWidth() : 0;
        Float angle = lesion.getAngle() != null ? lesion.getAngle() : 0;
        Float area = lesion.getArea() != null ? lesion.getArea() : 0;
        Integer fallDownNumber = lesion.getFallDownNumber() != null ? lesion.getFallDownNumber() : 0;
        String roadType = lesion.getRoadType() != null ? lesion.getRoadType() : FrameMeta.RoadType.ROAD_TYPE_UNKNOWN.toString();
        Integer heightDiff = lesion.getHeightDiff() != null ? lesion.getHeightDiff().intValue() : 0;
        SeverityType severityType = lesion.getSeverityType() != null ? lesion.getSeverityType() : SeverityType.SEVERE;
        //subjects
        HitSubject hitSubject = new HitSubject();
        hitSubject.setRelBbox(lesion.getBox());
        hitSubject.setWidth(width);
        hitSubject.setLength(length);
        hitSubject.setArea(area);
        hitSubject.setAngle(angle);
        hitSubject.setHeightDiff(heightDiff);
        hitSubject.setFallDownNumber(fallDownNumber);
        hitSubject.setSeverityType(severityType);
        hitSubject.setType(lesion.getType());
        hitSubject.setRoadType(roadType);
        hitSubject.setNeedPushOut(Boolean.TRUE);
        hitSubject.setHeadCount(0);
        hitSubject.setComfortRate(0f);
        hitSubject.setStatus(HitStatusEnum.NEW);
        hit.setSubjects(Lists.newArrayList(hitSubject));
        //attrs
        HitAttrs hitAttrs = new HitAttrs();
        hitAttrs.setGpsLocation(gpsLocation);
        hitAttrs.setLocation(Lists.newArrayList(gpsLocation.getLongitude(), gpsLocation.getLatitude()));
        hitAttrs.setStatus(HitStatusEnum.NEW);
        hitAttrs.setCarId(inspectPicture.getCarId());
        hitAttrs.setConfirmation(Confirmation.builder().status(
                Confirmation.ConfirmationStatus.TO_BE_CONFIRMED).confirmTime(System.currentTimeMillis() / 1000).build());
        OSSObject imageOssFile = aliyunOSSUtil.getFileByUrl(inspectPicture.getUrl());
        byte[] originImageBytes = imageOssFile.getObjectContent().readAllBytes();
        String originImageBase64 = ImageUtil.bytes2Base64(originImageBytes);
        String sceneImageName = StringUtils.substringAfter(inspectPicture.getUrl(), ".com/").replace("aicar138", "disease138");
        log.info("InspectService: inspect hit pic url: {}", sceneImageName);
        hitAttrs.setSceneImageName(sceneImageName);
        byte[] drawFrameImageBytes = ImageUtil.drawFrame(originImageBase64, new ArrayList<>(), Lists.newArrayList(lesion.getBox()));
        AliyunOssResult drawFrameImageResult = aliyunOSSUtil.uploadImg(sceneImageName + "_" + idx + "-draw.jpg", drawFrameImageBytes);
        if (drawFrameImageResult.getCode() == HttpStatus.SC_OK) {
            hitAttrs.setFrameImageUrl(drawFrameImageResult.getUrl());
        } else {
            log.info("upload image failed, hitId: {}, hitImage64:{}", hit.getId(), originImageBase64);
        }
        hitAttrs.setSceneImage(inspectPicture.getUrl());
        hitAttrs.setHandleCompanyCode(companyId);
        hitAttrs.setHandleCompany(companyName);
        hitAttrs.setRoadName(roadInfo);
        hitAttrs.setRoadType(roadType);
        hitAttrs.setLimitHour(limitHour);
        hitAttrs.setSource(SourceEnum.TAG.toString());
        hitAttrs.setLoop(loop);
        hit.setAttrs(hitAttrs);
        //list
        HistoryHit historyHit = new HistoryHit();
        historyHit.setType(lesion.getType());
        historyHit.setHitTime(timestamp);
        historyHit.setSeverityType(severityType);
        historyHit.setWidth(width);
        historyHit.setAngle(angle);
        historyHit.setHeightDiff(heightDiff);
        historyHit.setLength(length);
        historyHit.setArea(area);
        historyHit.setFallDownNumber(fallDownNumber);
        historyHit.setHeadCount(0);
        historyHit.setComfortRate(0f);
        historyHit.setSubjects(Lists.newArrayList(hitSubject));
        //简化版hitAttrs
        HistoryHitAttrs historyHitAttrs = HistoryHitAttrs.builder().status(HitStatusEnum.NEW).carId(inspectPicture.getCarId())
                .gpsLocation(gpsLocation).sceneImage(inspectPicture.getUrl()).build();
        historyHit.setAttrs(historyHitAttrs);
        historyHit.setRoadType(roadType);
        hit.setList(Lists.newArrayList(historyHit));
        hit.setCreationTime(System.currentTimeMillis() / 1000);
        hit.setLastModificationTime(System.currentTimeMillis() / 1000);
        hit.setSeverityType(severityType);
        hit.setWidth(width);
        hit.setLength(length);
        hit.setArea(area);
        hit.setAngle(angle);
        hit.setHeightDiff(heightDiff);
        hit.setFallDownNumber(fallDownNumber);
        hit.setHeadCount(0);
        hit.setComfortRate(0f);
        hit.setRoadType(roadType);
        hit.setNeedPushOut(Boolean.TRUE);
        hit.setScene(scene);
        hit.setClassification(classification);
        hitDao.saveOrUpdate(hit);
        return hitId;
    }
}
